package com.mai4j.maiadmin.configure;

import com.mai4j.maiadmin.model.UserPrincipal;
import com.mai4j.maiadmin.support.cache.Session;
import com.mai4j.maiadmin.support.security.JwtUtils;
import com.mai4j.maiadmin.support.security.SecurityUtils;
import com.mai4j.maiadmin.support.web.utils.CookieUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;

/**
 * 微信公众号请关注: 开源螺丝钉
 * <br>
 * 码云请关注: <a href="https://gitee.com/xiyoufang">https://gitee.com/xiyoufang</a>
 * <br>
 * 哔哩哔哩请关注: <a href="https://space.bilibili.com/438927834">https://space.bilibili.com/438927834</a>
 *
 * @author xiyoufang
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) // 用于启用注解支持
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    private final MaiProperties maiProperties;

    public SecurityConfig(MaiProperties maiProperties) {
        this.maiProperties = maiProperties;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                // 静态资源
                .authorizeRequests().antMatchers(WebMvcConfig.RES_PATH).permitAll().and()
                // 默认所有请求不需要权限，需要权限的手动在controller添加
                .authorizeRequests().anyRequest().permitAll().and()
                // 使用STATELESS模式, 通过session缓存实现Session功能
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .headers().cacheControl().and().and()
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
        return new InMemoryUserDetailsManager();
    }

    /**
     * 解析cookies中的Jwt进行权限校验
     *
     * @return jwtAuthenticationFilter
     */
    private OncePerRequestFilter jwtAuthenticationFilter() {

        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
                String authorization = request.getHeader("Authorization");
                if (StringUtils.isNotBlank(authorization)) {
                    String[] parsed = authorization.split(" ");
                    if (parsed.length == 2
                            && "Bearer".equalsIgnoreCase(parsed[0])
                            && JwtUtils.verify(maiProperties.getJwtKey(), parsed[1])
                            && Session.isValid(parsed[1])) { // 授权头jwt有效
                        UserPrincipal userPrincipal = JwtUtils.parse(maiProperties.getJwtKey(), parsed[1], UserPrincipal.class);
                        SecurityUtils.login(parsed[1], userPrincipal, Collections.emptySet()); // 有效则进入登录状态
                    }
                } else {
                    String jwt = CookieUtil.getValue("jwt");
                    if (StringUtils.isNotBlank(jwt)
                            && JwtUtils.verify(maiProperties.getJwtKey(), jwt)
                            && Session.isValid(jwt)) { // 授权头jwt有效
                        UserPrincipal userPrincipal = JwtUtils.parse(maiProperties.getJwtKey(), jwt, UserPrincipal.class);
                        SecurityUtils.login(jwt, userPrincipal, Collections.emptySet()); // 有效则进入登录状态
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }
}